﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Lenic.DI.Drivers;
using Lenic.DI.Lifetimes;

namespace Lenic.DI
{
    /// <summary>
    /// DI 容器类
    /// </summary>
    [DebuggerStepThrough]
    public sealed class Container : IContainer
    {
        #region Private Properties

        /// <summary>
        /// 获取或设置 DI 项的容器.
        /// </summary>
        private IStore Factories { get; set; }

        #endregion Private Properties

        #region Entrance

        private static readonly IContainer instance = new Container();

        /// <summary>
        /// Initializes a new instance of the <see cref="Container"/> class.
        /// </summary>
        /// <param name="store">The store.</param>
        public Container(IStore store = null)
        {
            Factories = store ?? new DefaultStore();
            Tag = new Dictionary<string, object>();
        }

        /// <summary>
        /// 获取单例的 <see cref="Container"/> 类的实例对象。
        /// </summary>
        public static IContainer Instance { get { return instance; } }

        #endregion Entrance

        #region Business Methods

        /// <summary>
        /// 获取当前对象关联的扩展属性集合。
        /// </summary>
        /// <value>
        /// 当前对象关联的扩展属性集合。
        /// </value>
        public IDictionary<string, object> Tag { get; private set; }

        /// <summary>
        /// 向容器中注册组件
        /// </summary>
        /// <typeparam name="TService">委托返回值类型</typeparam>
        /// <param name="component">待注册的组件实例对象</param>
        /// <returns>修改后的自身</returns>
        public IContainer Register<TService>(Registration<TService> component)
        {
            lock (this)
            {
                try
                {
                    Factories.Add(component.ServiceType, component.Name, component.Value);
                }
                catch
                {
                    throw new RegisterException(component.ServiceType, component.Name);
                }
            }

            return this;
        }

        /// <summary>
        /// 解析的具体实现
        /// </summary>
        /// <param name="serviceType">待解析的类型</param>
        /// <param name="name">解析类型的命名名称</param>
        /// <param name="lifetime">解析的实例对象.</param>
        /// <returns><c>true</c> 表示成功获取; 否则返回 <c>false</c> .</returns>
        public bool TryResolve(Type serviceType, string name, out ILifetime lifetime)
        {
            var result = Factories.TryGetValue(serviceType, name, out lifetime);
            if (!result && OnResolveError != null)
            {
                lock (this)
                {
                    if (!Factories.TryGetValue(serviceType, name, out lifetime))
                    {
                        OnResolveError(this, serviceType, name, ref lifetime);
                        result = (lifetime != null);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 解析的具体实现。
        /// </summary>
        /// <param name="serviceType">待解析的类型</param>
        /// <param name="lifetimes">解析的实例对象数组。</param>
        /// <returns>
        ///   <c>true</c> 表示成功获取; 否则返回 <c>false</c> 。
        /// </returns>
        public bool TryResolve(Type serviceType, out ILifetime[] lifetimes)
        {
            lifetimes = Factories.GetValues(serviceType).ToArray();
            if (!lifetimes.Any())
            {
                ILifetime lifetime = null;
                OnResolveError(this, serviceType, null, ref lifetime);

                if (lifetime == null)
                {
                    lifetimes = new ILifetime[0];
                    return false;
                }
                {
                    lifetimes = new ILifetime[] { lifetime };
                    return true;
                }
            }
            return true;
        }

        #endregion Business Methods

        #region Events

        /// <summary>
        /// 在容器解析 ILifetime 对象失败后触发
        /// </summary>
        public event Register OnResolveError;

        #endregion Events

        #region IDisposable Members

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
        /// </summary>
        public void Dispose()
        {
            Factories.Dispose();
            GC.SuppressFinalize(this);
        }

        #endregion IDisposable Members

        #region IEnumerable<ILifetime> 成员

        /// <summary>
        /// 返回一个循环访问集合的枚举器。
        /// </summary>
        /// <returns>
        /// 可用于循环访问集合的 <see cref="T:System.Collections.IEnumerator" /> 对象。
        /// </returns>
        public IEnumerator<ILifetime> GetEnumerator()
        {
            return Factories.GetEnumerator();
        }

        #endregion IEnumerable<ILifetime> 成员

        #region IEnumerable 成员

        /// <summary>
        /// 返回一个循环访问集合的枚举器。
        /// </summary>
        /// <returns>
        /// 可用于循环访问集合的 <see cref="T:System.Collections.IEnumerator" /> 对象。
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion IEnumerable 成员
    }
}